package licode.unisop.single.platform.infrastructure.repository.dao;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import licode.unisop.provider.conf.SiAssetState;
import licode.unisop.provider.info.AssetHoldPageInfo;
import licode.unisop.provider.info.HoldAssetPageInfo;
import licode.unisop.provider.info.SiRemoveAllRelAsset;
import licode.unisop.provider.vo.SiAssetRelEntity;
import licode.unisop.provider.vo.SiPageResult;
import licode.unisop.single.platform.application.gateway.PlatAssetRelDao;
import licode.unisop.single.platform.application.info.*;
import licode.unisop.single.platform.infrastructure.assembler.UniPlatformSingleAssembler;
import licode.unisop.single.platform.infrastructure.repository.mapper.PlatAssetRelMapper;
import licode.unisop.single.platform.infrastructure.repository.po.PlatAssetRelPO;
import licode.unisop.single.platform.infrastructure.repository.po.PlatformAssetPO;
import licode.unisop.single.platform.infrastructure.utils.PageUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * uni-platform-single
 *
 * @author licode
 * @date 2016-08-27 15:30:59
 */
@Component
public class PlatAssetRelDaoImpl
        extends MPJBaseServiceImpl<PlatAssetRelMapper, PlatAssetRelPO>
        implements PlatAssetRelDao {
    @Resource
    private UniPlatformSingleAssembler uniPlatformSingleAssembler;

    @Override
    public void add(SiAssetRelEntity item) {
        super.save(uniPlatformSingleAssembler.fromPlatAssetRelEntity(item));
    }

    @Override
    public void addBatch(List<SiAssetRelEntity> items) {
        super.saveBatch(items.stream()
                .map(item -> uniPlatformSingleAssembler.fromPlatAssetRelEntity(item))
                .collect(Collectors.toList()));
    }

    @Override
    public void update(SiAssetRelEntity item) {
        super.updateById(uniPlatformSingleAssembler.fromPlatAssetRelEntity(item));
    }

    @Override
    public void updateBatch(List<SiAssetRelEntity> items) {
        super.updateBatchById(items.stream()
                .map(item -> uniPlatformSingleAssembler.fromPlatAssetRelEntity(item))
                .collect(Collectors.toList()));
    }

    @Override
    public void removeWithId(Serializable id) {
        super.removeById(id);
    }

    @Override
    public SiAssetRelEntity getWithId(Serializable id) {
        return uniPlatformSingleAssembler.fromPlatAssetRel(super.getById(id));
    }

    @Override
    public void removeAssets(RemoveHoldAssetsIn info) {
        super.remove(Wrappers.<PlatAssetRelPO>lambdaUpdate()
                .eq(PlatAssetRelPO::getOwnerId, info.getPlatformId())
                .in(PlatAssetRelPO::getAssetId, info.getHoldIds())
                .eq(PlatAssetRelPO::getAssetType, info.getHoldType())
                .in(null != info.getAssetIds() && !info.getAssetIds().isEmpty(),
                        PlatAssetRelPO::getTargetId, info.getAssetIds())
                .eq(StrUtil.isNotBlank(info.getAssetType()),
                        PlatAssetRelPO::getTargetType, info.getAssetType()));
    }

    @Override
    public void removeHolders(RemoveAssetHoldsIn info) {
        super.remove(Wrappers.<PlatAssetRelPO>lambdaUpdate()
                .eq(PlatAssetRelPO::getOwnerId, info.getPlatformId())
                .eq(PlatAssetRelPO::getTargetId, info.getAssetId())
                .eq(PlatAssetRelPO::getTargetType, info.getAssetType())
                .eq(PlatAssetRelPO::getAssetType, info.getHoldType())
                .in(null != info.getHoldIds() && !info.getHoldIds().isEmpty(),
                        PlatAssetRelPO::getAssetId, info.getHoldIds()));
    }

    @Override
    public void removeAll(SiAssetRemove info) {
        super.remove(Wrappers.<PlatAssetRelPO>lambdaUpdate()
                .eq(PlatAssetRelPO::getOwnerId, info.getPlatformId())
                .in(PlatAssetRelPO::getAssetId, info.getIds()));
        super.remove(Wrappers.<PlatAssetRelPO>lambdaUpdate()
                .eq(PlatAssetRelPO::getOwnerId, info.getPlatformId())
                .in(PlatAssetRelPO::getTargetId, info.getIds()));
    }

    @Override
    public void removeAllRelAsset(SiRemoveAllRelAsset req) {
        super.remove(Wrappers.<PlatAssetRelPO>lambdaUpdate()
                .eq(PlatAssetRelPO::getOwnerId, req.getPlatformId())
                .eq(PlatAssetRelPO::getAssetId, req.getAssetId())
                .eq(PlatAssetRelPO::getAssetType, req.getAssetType()));
        super.remove(Wrappers.<PlatAssetRelPO>lambdaUpdate()
                .eq(PlatAssetRelPO::getOwnerId, req.getPlatformId())
                .eq(PlatAssetRelPO::getTargetId, req.getAssetId())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType()));
    }

    @Override
    public List<SiAssetRelEntity> getRelations(RelationIdInfo info) {
        return convertAssetRel(buildCondition(info).list());
    }

    @Override
    public SiPageResult<SiAssetRelEntity> getRelationsPage(RelationIdPage info) {
        Page<PlatAssetRelPO> page = new Page<>(info.getCurrent(), info.getPageSize());

        page = buildCondition(info.getRelationId()).page(page);

        return PageUtil.convertPage(page, this::convertAssetRel);
    }

    @Override
    public SiPageResult<SiAssetRelEntity> findHoldRefAssetPage(HoldAssetPageInfo req) {
        IPage<PlatAssetRelPO> page = new Page<>(req.getCurrent(), req.getPageSize());

        page = getBaseMapper().selectJoinPage(page, PlatAssetRelPO.class, new MPJLambdaWrapper<PlatAssetRelPO>()
                .selectAll(PlatAssetRelPO.class)
                .eq(PlatAssetRelPO::getOwnerId, req.getOwnerId())
                .eq(PlatAssetRelPO::getAssetId, req.getHoldId())
                .eq(PlatAssetRelPO::getAssetType, req.getHoldType())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType())
                .in(null != req.getAssetIds() && !req.getAssetIds().isEmpty(),
                        PlatAssetRelPO::getTargetId, req.getAssetIds())
                .orderByDesc(PlatAssetRelPO::getUpdateTime));

        return PageUtil.convertPage(page, this::convertAssetRel);
    }

    @Override
    public SiPageResult<SiAssetRelEntity> findAssetRefHoldPage(AssetHoldPageInfo req) {
        IPage<PlatAssetRelPO> page = new Page<>(req.getCurrent(), req.getPageSize());

        page = getBaseMapper().selectJoinPage(page, PlatAssetRelPO.class, new MPJLambdaWrapper<PlatAssetRelPO>()
                .selectAll(PlatAssetRelPO.class)
                .eq(PlatAssetRelPO::getOwnerId, req.getOwnerId())
                .eq(PlatAssetRelPO::getTargetId, req.getAssetId())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType())
                .eq(PlatAssetRelPO::getAssetType, req.getHoldType())
                .in(null != req.getHoldIds() && !req.getHoldIds().isEmpty(),
                        PlatAssetRelPO::getAssetId, req.getHoldIds())
                .orderByDesc(PlatAssetRelPO::getUpdateTime));

        return PageUtil.convertPage(page, this::convertAssetRel);
    }

    @Override
    public SiPageResult<SiAssetRelEntity> findHoldAssetPage(HoldAssetPageInfo req) {
        IPage<PlatAssetRelPO> page = new Page<>(req.getCurrent(), req.getPageSize());

        page = getBaseMapper().selectJoinPage(page, PlatAssetRelPO.class, new MPJLambdaWrapper<PlatAssetRelPO>()
                .selectAll(PlatAssetRelPO.class)
                .innerJoin(PlatformAssetPO.class, PlatformAssetPO::getId, PlatAssetRelPO::getTargetId)
                .eq(PlatAssetRelPO::getOwnerId, req.getOwnerId())
                .eq(PlatAssetRelPO::getAssetId, req.getHoldId())
                .eq(PlatAssetRelPO::getAssetType, req.getHoldType())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .orderByDesc(PlatAssetRelPO::getUpdateTime));

        return PageUtil.convertPage(page, this::convertAssetRel);
    }

    @Override
    public SiPageResult<SiAssetRelEntity> findAssetHoldPage(AssetHoldPageInfo req) {
        IPage<PlatAssetRelPO> page = new Page<>(req.getCurrent(), req.getPageSize());

        page = getBaseMapper().selectJoinPage(page, PlatAssetRelPO.class, new MPJLambdaWrapper<PlatAssetRelPO>()
                .selectAll(PlatAssetRelPO.class)
                .innerJoin(PlatformAssetPO.class, PlatformAssetPO::getId, PlatAssetRelPO::getAssetId)
                .eq(PlatAssetRelPO::getOwnerId, req.getOwnerId())
                .eq(PlatAssetRelPO::getTargetId, req.getAssetId())
                .eq(PlatAssetRelPO::getTargetType, req.getAssetType())
                .eq(PlatAssetRelPO::getAssetType, req.getHoldType())
                .ne(PlatformAssetPO::getState, SiAssetState.AT_DELETED)
                .orderByDesc(PlatAssetRelPO::getUpdateTime));

        return PageUtil.convertPage(page, this::convertAssetRel);
    }

    private LambdaQueryChainWrapper<PlatAssetRelPO> buildCondition(RelationIdInfo info) {
        return super.lambdaQuery()
                .eq(PlatAssetRelPO::getOwnerId, info.getOwnerId())
                .eq(StrUtil.isNotBlank(info.getRelType()), PlatAssetRelPO::getRelationType, info.getRelType())
                .eq(StrUtil.isNotBlank(info.getAssetId()), PlatAssetRelPO::getAssetId, info.getAssetId())
                .eq(StrUtil.isNotBlank(info.getAssetType()), PlatAssetRelPO::getAssetType, info.getAssetType())
                .in((null != info.getAssetIds() && !info.getAssetIds().isEmpty()),
                        PlatAssetRelPO::getAssetId, info.getAssetIds())
                .eq(StrUtil.isNotBlank(info.getTargetId()), PlatAssetRelPO::getTargetId, info.getTargetId())
                .eq(StrUtil.isNotBlank(info.getTargetType()), PlatAssetRelPO::getTargetType, info.getTargetType())
                .in((null != info.getTargetIds() && !info.getTargetIds().isEmpty()),
                        PlatAssetRelPO::getTargetId, info.getTargetIds());
    }

    private List<SiAssetRelEntity> convertAssetRel(List<PlatAssetRelPO> relList) {
        if (null != relList) {
            return relList.stream().map(item -> uniPlatformSingleAssembler.fromPlatAssetRel(item))
                    .collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
    }

}
